package com.lonely.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lonely.common.constant.UserConstants;
import com.lonely.common.enums.CommonStatus;
import com.lonely.common.utils.SecurityUtils;
import com.lonely.system.domain.entity.SysMenu;
import com.lonely.system.domain.entity.SysRole;
import com.lonely.system.domain.entity.SysRoleMenu;
import com.lonely.system.domain.vo.system.menu.QueryRoleButtonVo;
import com.lonely.system.mapper.SysRoleMenuMapper;
import com.lonely.system.service.ISysMenuService;
import com.lonely.system.service.ISysRoleMenuService;
import com.lonely.system.service.ISysRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author: 黄志标
 * @date: 2025/5/26 13:29
 * @description: 角色和菜单关联表服务实现类
 */
@Service
public class SysRoleMenuServiceImpl extends ServiceImpl<SysRoleMenuMapper, SysRoleMenu> implements ISysRoleMenuService {

    @Autowired
    private ISysMenuService sysMenuService;

    @Autowired
    private ISysRoleService sysRoleService;

    /**
     * 根据角色id获取角色绑定的菜单id集合
     *
     * @param roleId
     * @return
     */
    @Override
    public List<Long> getRoleMenusByRoleId(Long roleId) {
        return super.getBaseMapper().getRoleMenusByRoleId(roleId);
    }

    /**
     * 批量根据角色id获取角色绑定的菜单id集合
     *
     * @param roleIds
     * @return
     */
    @Override
    public List<String> batchGetMenuPermsByRoleId(List<Long> roleIds) {
        if (CollUtil.isEmpty(roleIds)) {
            return new ArrayList<>();
        }
        return super.getBaseMapper().batchGetMenuPermsByRoleId(roleIds);
    }

    /**
     * 根据角色id获取角色绑定的按钮id集合
     *
     * @param roleId
     * @return
     */
    @Override
    public List<Long> getRoleButtonsByRoleId(Long roleId) {
        return super.getBaseMapper().getRoleButtonsByRoleId(roleId);
    }

    /**
     * 获取该角色选中的所有菜单下的所有按钮集合
     *
     * @param roleId
     * @return
     */
    @Override
    public List<QueryRoleButtonVo> getButtonsFromSelectedMenuByRoleId(Long roleId) {

        // 获取该角色绑定的所有菜单id集合
        List<Long> selectedMenuIds = this.getRoleMenusByRoleId(roleId);
        if (CollUtil.isEmpty(selectedMenuIds)) {
            return new ArrayList<>();
        }

        // 获取选中的菜单下的所有按钮集合
        return Optional.ofNullable(this.sysMenuService.list(new LambdaQueryWrapper<SysMenu>()
                .in(SysMenu::getParentId, selectedMenuIds)
                .eq(SysMenu::getMenuType, UserConstants.TYPE_BUTTON)
                .orderByAsc(SysMenu::getId)
        )).orElse(new ArrayList<>()).stream().map(x -> {
            QueryRoleButtonVo queryRoleButtonVo = new QueryRoleButtonVo();
            queryRoleButtonVo.setButtonId(x.getId());
            queryRoleButtonVo.setButtonName(x.getMenuName());
            return queryRoleButtonVo;
        }).collect(Collectors.toList());
    }

    /**
     * 批量保存角色和菜单关联信息
     *
     * @param roleId
     * @param menuIds
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchSaveRoleMenus(Long roleId, List<Long> menuIds) {
        Assert.notNull(roleId, "参数错误(roleId)");

        // 清空当前角色id的所有菜单(物理删除)
        super.getBaseMapper().batchDeleteRoleMenuByRoleIds(ListUtil.of(roleId));

        // 构建角色菜单关系
        if (CollUtil.isEmpty(menuIds)) {
            return;
        }

        // 过滤出合法有效的菜单id
        List<SysMenu> actualMenus = this.sysMenuService.list(new LambdaQueryWrapper<SysMenu>().in(SysMenu::getId, menuIds)
                .eq(SysMenu::getStatus, CommonStatus.ENABLE.code)
        );

//        List<Long> actualMenuIds = actualMenus.stream().map(BaseEntity::getId).collect(Collectors.toList());
        if (CollUtil.isEmpty(actualMenus)) {
            return;
        }

        // 找出获取包含所有父级的菜单节点id
        List<Long> includedParentMenuIds = actualMenus.stream()
                .map(SysMenu::getAncestors)
                .filter(StrUtil::isNotBlank)
                .flatMap(x -> CollUtil.newArrayList(x.split(",")).stream())
                .map(Convert::toLong)
                .filter(x -> x != 0L)
                .distinct().collect(Collectors.toList());


        List<SysRoleMenu> sysRoleMenus = includedParentMenuIds.stream().map(currentMenuId -> {
            SysRoleMenu sysRoleMenu = new SysRoleMenu();
            sysRoleMenu.setId(null);
            sysRoleMenu.setRoleId(roleId);
            sysRoleMenu.setMenuId(currentMenuId);
            sysRoleMenu.setCreateBy(SecurityUtils.getUserId());
            sysRoleMenu.setUpdateBy(SecurityUtils.getUserId());
            return sysRoleMenu;
        }).collect(Collectors.toList());

        super.saveBatch(sysRoleMenus);
    }

    /**
     * 删除指定角色id关联的所有菜单信息
     *
     * @param roleId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByRoleId(Long roleId) {
        Assert.notNull(roleId, "参数错误(roleId)");

        // 校验角色id是否存在
        SysRole sysRole = this.sysRoleService.getById(roleId);
        Assert.notNull(sysRole, "角色不存在");

        // 清空当前角色id的所有菜单(物理删除)
        super.getBaseMapper().batchDeleteRoleMenuByRoleIds(ListUtil.of(roleId));
    }

    /**
     * 批量删除指定角色id关联的所有菜单信息
     *
     * @param roleIds
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDeleteByRoleIds(List<Long> roleIds) {
        if (CollUtil.isEmpty(roleIds)) {
            return;
        }

        // 清空当前角色id的所有菜单(物理删除)
        super.getBaseMapper().batchDeleteRoleMenuByRoleIds(roleIds);
    }
}
